在 NestJS 中,DI(Dependency Injection,依賴注入)是整個框架的核心機制,開發者只要在 constructor 寫一行 private readonly postService: PostService,框架就會自動幫你注入實例——聽起來很神奇,但這套機制可不是無條件運作的。
今天我們就來拆解三個初學者最容易踩的 DI 陷阱。
當你在 Controller 的建構子中注入了 service:
@Controller('post')
export class PostController {
constructor(private readonly postService: PostService) {}
}
但忘記在對應的 Module 中宣告它:
@Module({
// ❌ 陷阱:PostController 注入了 PostService,但未加入 providers 中
// providers: [PostService],
controllers: [PostController],
})
export class PostModule {}
此時會出現錯誤:
[Error]: Nest cannot export a provider/module that is not a part of the currently processed module (PostModule). Please verify whether the exported PostService is available in this particular context.
Possible Solutions:
-Is PostService part of the relevant providers/imports within PostModule?
如果 UserService 想要使用 PostService 提供的共用邏輯:
@Injectable()
export class UserService {
constructor(private readonly postService: PostService) {}
}
即使我們在 UserModule 中匯入了 PostModule,但如果 PostModule 沒有把 PostService 匯出,一樣會報錯:
@Module({
imports: [PostModule],
controllers: [UserController],
providers: [UserService],
})
export class UserModule {}
@Module({
providers: [PostService],
controllers: [PostController],
// ❌ 陷阱:UserService 欲使用 PostService,但此處未匯出
})
export class PostModule {}
[Nest] 16311 - 09/16/2026, 5:25:28 PM ERROR [ExceptionHandler] UnknownDependenciesException [Error]: Nest can't resolve dependencies of the PostController (?). Please make sure that the argument PostService at index [0] is available in the PostModule module.
Potential solutions:
- Is PostModule a valid NestJS module?
- If PostService is a provider, is it part of the current PostModule?
- If PostService is exported from a separate @Module, is that module imported within PostModule?
@Module({
imports: [ /* the Module containing PostService */ ]
})
接續上面,假設 PostModule 已經匯出了 PostService,但作為需求方模組的 UserModule 卻忘記引入它:
@Module({
// ❌ 陷阱:UserService 注入了 PostService,但未匯入提供它的 PostModule
// imports: [PostModule],
controllers: [UserController],
providers: [UserService],
})
export class UserModule {}
ERROR [ExceptionHandler] UnknownDependenciesException [Error]: Nest can't resolve dependencies of the UserService (?). Please make sure that the argument PostService at index [0] is available in the UserModule module.
Potential solutions:
-Is UserModule a valid NestJS module?
-If PostService is a provider, is it part of the current UserModule?
-If PostService is exported from a separate @Module, is that module imported within UserModule?
@Module({
imports: [ /* the Module containing PostService */ ]
})
當你寫下:
@Injectable()
export class UserService {
constructor(private readonly postService: PostService) {}
}
NestJS 其實不會去全域搜尋全專案哪裡有 PostService 這個 class。它只會在意一件事:「在 UserModule 當前能管轄的範圍內,到底知不知道 PostService 是從哪來的?」
Nest 會根據 @Module() 中的 metadata 建立模組與 provider 之間的關係。當它建立 controller 或 provider 實例時,會解析 constructor 所需要的每一個 dependency。
以 UserService 為例,Nest 需要找到 PostService。
在一般的 Module 情境下,UserModule 能使用的 provider 主要來自兩個地方:
UserModule 自己 providers 中註冊的 providerUserModule 的 imports 所引入之模組,透過 exports 公開出來的 provider這也正好對應 @Module() 中三個最重要的陣列:
| 屬性 | 白話理解 | 作用 |
|---|---|---|
providers |
我自己有哪些東西 | 註冊由本模組管理的 provider |
exports |
我願意公開哪些東西 | 將 provider 公開給其他模組使用 |
imports |
我要接上哪些模組 | 取得其他模組所公開的 provider |
所以這三個陷阱,其實不是三套不同規則,而是同一條 provider 可見性路徑斷在不同位置:
| 陷阱 | 斷點 | 結果 |
|---|---|---|
| 陷阱一 | PostService 沒有註冊進 PostModule.providers |
PostModule 內部自己就找不到 PostService |
| 陷阱二 | PostModule 沒有 exports: [PostService] |
PostService 存在,但被封裝在模組內,沒有對外公開 |
| 陷阱三 | UserModule 沒有 imports: [PostModule] |
PostService 已對外公開,但 UserModule 尚未建立連線 |
當你再遇到 Nest can't resolve dependencies...,請不要慌張,跟著這三步循序排查:
先看終端機後半句:哪個 Controller / Service 缺少了哪個依賴?available in the XXX module 寫的是哪個模組?
缺少的 service 是否在該模組的 providers 陣列中?(若是控制器缺 Service,看它自己的 Module)
exports: [XxxService]?imports: [XxxModule]?只要掌握這三個步驟,就能排除很大一部分常見的 NestJS DI 啟動錯誤。
providers 中。exports,需求方有 imports。